package com.bbc.commonbackstage.platform.utils;

import com.bbc.commonbackstage.common.constant.Constants;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang3.StringUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 二维码工具类
 *
 * @author Wyy
 * @date 2022/1/12
 */
public class BarcodeUtils {

    /**
     * 二维码颜色 默认是黑色
     */
    private static final int QR_COLOR = 0xFF000000;

    /**
     * 背景颜色，默认为白色
     */
    private static final int BG_WHITE = 0xFFFFFFFF;

    /**
     * 生成的二维码的宽度，单位（像素）
     */
    private static final int WIDTH = 215;

    /**
     * 生成的二维码的高度，单位（像素）
     */
    private static final int HEIGHT = 215;

    /**
     * 加文字的二维码的高度，单位（像素）
     */
    private static final int WORD_HEIGHT = 265;

    /**
     * 用于设置QR二维码的参数
     */
    private static final Map<EncodeHintType, Object> HINTS = new HashMap<EncodeHintType, Object>() {
        private static final long serialVersionUID = 1L;
        {
            // 设置QR二维码的纠错级别（H为最高级别）具体级别信息
            put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            // 设置编码方式为utf-8
            put(EncodeHintType.CHARACTER_SET, Constants.UTF8);
            put(EncodeHintType.MARGIN, 0);
        }
    };


    /**
     * 设置Graphics2D的属性（抗锯齿）
     *
     * @param graphics2D 2D图形
     */
    private static void setGraphics2D(Graphics2D graphics2D) {
        graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
        Stroke stroke = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
        graphics2D.setStroke(stroke);
    }


    /**
     * 生成二维码图片存储到filePath中
     *
     * @param content  二维码内容
     * @param filePath 成二维码图片保存路径
     * @param name     图片名称
     * @return 结果
     */
    public static boolean createImg(String content, String name, String filePath) {
        boolean flag = false;

        try {
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, HINTS);

            // 图片输出路径
            //String code = content; // 设备编号

            File file = new File(filePath + name + ".jpg");
            if (!file.exists()) {
                // 如果文件夹不存在则创建
                flag = file.mkdirs();
            }
            // 输出二维码图片到文件夹
            MatrixToImageWriter.writeToPath(bitMatrix, "jpg", file.toPath());
            flag = true;

        } catch (Exception e) {
            e.printStackTrace();
        }

        return flag;
    }

    /**
     * 生成二维码的方法
     */
    public static BufferedImage qrCode(String content) {
        // 定义二维码的宽、高

        // EncodeHintType 它是一个二维码的特征信息常量
        Map<EncodeHintType, Object> hints = new HashMap<>();

        // 比如，纠错能力
        hints.put(EncodeHintType.CHARACTER_SET, Constants.UTF8);
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix;

        try {
            // 生成一个二维码的工具
            bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);
            // 第一个参数是信息块的颜色
            MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000000, 0XFFFFFFFF);
            // 第一个参数是二维码数据，它描述了那个位置有信息，那个位置没有信息，第二个参数描述了填充成图片的时候使用的颜色
            return MatrixToImageWriter.toBufferedImage(bitMatrix, matrixToImageConfig);
        } catch (WriterException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 新的图片，把带logo的二维码下面加上文字
     *
     * @param image 带缓冲的图像
     * @param words 文字
     * @return 处理好地带缓冲图像
     */
    private static BufferedImage insertWords(BufferedImage image, String words) {
        // 前置校验
        if(StringUtils.isEmpty(words)) {
            return null;
        }

        //创建一个带透明色的BufferedImage对象
        BufferedImage outImage = new BufferedImage(WIDTH, WORD_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
        Graphics2D outImageGraphics = outImage.createGraphics();
        setGraphics2D(outImageGraphics);

        // 画二维码到新的面板
        outImageGraphics.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
        // 画文字到新的面板
        //Color color = new Color(183, 183, 183);
        outImageGraphics.setColor(Color.black);
        // 字体、字型、字号
        outImageGraphics.setFont(new Font("宋体", Font.BOLD, 18));
        //文字长度
        int strWidth = outImageGraphics.getFontMetrics().stringWidth(words);
        words = new String(words.getBytes(), StandardCharsets.UTF_8);
        //总长度减去文字长度的一半  （居中显示）
        /*int wordStartX = (WIDTH - strWidth) / 2;
        //height + (outImage.getHeight() - height) / 2 + 12
        int wordStartY = HEIGHT + 20;
        // 画文字
        outImageGraphics.drawString(words, 0, wordStartY);
        outImageGraphics.dispose();
        outImage.flush();*/
        if (strWidth > WIDTH) {
            // 长度过长就截取前面部分 然后换行
            String note1 = words.substring(0, words.length() / 2);
            String note2 = words.substring(words.length() / 2, words.length());
            int strWidth1 = outImageGraphics.getFontMetrics().stringWidth(note1);
            int strWidth2 = outImageGraphics.getFontMetrics().stringWidth(note2);
            outImageGraphics.drawString(note1, 0, HEIGHT + (outImage.getHeight() - HEIGHT) / 2);
            BufferedImage outImage2 = new BufferedImage(WIDTH, WORD_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D outg2 = outImage2.createGraphics();
            outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
            outg2.setColor(Color.black);
            // 字体、字型、字号
            outg2.setFont(new Font("宋体", Font.PLAIN, 18));
            // 画文字
            outg2.drawString(note2, 0, HEIGHT + (outImage2.getHeight() - HEIGHT) / 2 + 20);
            outg2.dispose();
            outImage2.flush();
            outImage = outImage2;
        }

        return outImage;
    }


    /**
     * 生成带logo的二维码图片 二维码下面带文字
     *
     * @param logoFile loge图片的路径
     * @param bgFile   背景图片的路径
     * @param codeFile 图片输出路径
     * @param qrUrl    二维码内容
     * @param words    二维码下面的文字
     */
    public static void drawLogoQRCode(File logoFile, File bgFile, File codeFile, String qrUrl, String words) {
        try {

            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            // 参数顺序分别为：编码内容，编码类型，生成图片宽度，生成图片高度，设置参数
            BitMatrix bm = multiFormatWriter.encode(qrUrl, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, HINTS);
            BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

            // 开始利用二维码数据创建Bitmap图片，分别设为黑（0xFFFFFFFF）白（0xFF000000）两色
            for (int x = 0; x < WIDTH; x++) {
                for (int y = 0; y < HEIGHT; y++) {
                    image.setRGB(x, y, bm.get(x, y) ? QR_COLOR : BG_WHITE);
                }
            }

            //把logo画到二维码上面
            if (Objects.nonNull(logoFile) && logoFile.exists()) {
                // 构建绘图对象
                Graphics2D g = image.createGraphics();
                setGraphics2D(g);
                // 读取Logo图片
                BufferedImage logo = ImageIO.read(logoFile);
                // 开始绘制logo图片 等比缩放：（width * 2 / 10 height * 2 / 10）不需缩放直接使用图片宽高
                //width * 2 / 5 height * 2 / 5  logo绘制在中心点位置
                g.drawImage(logo, WIDTH * 2 / 5, HEIGHT * 2 / 5, logo.getWidth(), logo.getHeight(), null);
                g.dispose();
                logo.flush();
            }

            // 新的图片，把带logo的二维码下面加上文字
            image = insertWords(image, words);

            // 非空判断
            if(Objects.nonNull(image)) {
                image.flush();
                ImageIO.write(image, "png", codeFile);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // Logo
        //File logoFile = new File("G://picture/03.png");
        // 背景图片
        //File bgFile = new File("G://picture/01.png");
        //生成图片
        File qrCodeFile = new File("F:\\桌面文件\\12.jpg");
        //二维码内容
        String url = "https://www.baidu.com";
        //二维码下面的文字
        String words = "PSD000001";
        drawLogoQRCode(null, null, qrCodeFile, url, words);
    }

}
